package net.vinote.smart.platform.pool;

import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

import net.vinote.smart.platform.pool.thread.ThreadPool;


public class PoolFactory
{
    private static Map<String, PoolFactory> cache;

    /**
     * 默认常驻内存大小
     */
    private int defaultSize = 50;

    /**
     * 可扩展元素上限
     */
    private int maxSize = 100;

    /**
     * 过期时长
     */
    private long expiredTime = 5000;

    /**
     * 池元素生命周期管理期
     */
    private PoolUnitManager poolUnitManager;

    /**
     * 常驻数据池对象
     */
    private ArrayBlockingQueue<Entry> poolList;

    /**
     * 临时数据池
     */
    private ArrayBlockingQueue<Entry> tempPoolList;

    public static PoolFactory getInstance(String poolName)
    {
        return getInstance(poolName, null, null);
    }

    public static PoolFactory getInstance(String poolName, String group)
    {
        return getInstance(poolName, group, null);
    }

    public static PoolFactory getInstance(String poolName,
            PoolUnitManager poolUnitManager)
    {
        return getInstance(poolName, "default", poolUnitManager);
    }

    public static PoolFactory getInstance(String poolName, String group,
            PoolUnitManager poolUnitManager)
    {
        if (cache == null)
        {
            synchronized (PoolFactory.class)
            {
                if (cache == null)
                {
                    cache = new HashMap<String, PoolFactory>();
                }
            }
        }
        PoolFactory factory = cache.get(poolName + "." + group);
        if (factory == null)
        {
            synchronized (PoolFactory.class)
            {
                if (factory == null)
                {
                    if (poolUnitManager == null)
                    {
                        throw new NullPointerException(
                                "PoolUnitManager is null");
                    }
                    factory = new PoolFactory(poolUnitManager);
                    cache.put(poolName + "." + group, factory);
                }
            }
        }
        return factory;
    }

    /**
     * 若数据池达到达到上限,则返回null
     * 从数据池中获取对象
     * @return
     */
    public Object getObject()
    {
        // 从常驻数据池中获取
        for (Entry entry : poolList)
        {
            if (!entry.refered)
            {
                entry.refered = true;
                entry.referedTime = System.currentTimeMillis();
                return entry.value;
            }
        }
        // 重新创建一个对象并存入临时数据池中
        if (tempPoolList == null)
        {
            synchronized (this)
            {
                if (tempPoolList == null)
                {
                    tempPoolList = new ArrayBlockingQueue<Entry>(maxSize);
                }
            }
        }
        if (tempPoolList.size() != maxSize)
        {
            synchronized (this)
            {
                if (tempPoolList.size() != maxSize)
                {
                    Entry entry = initEntry();
                    if (entry.value != null)
                    {
                        entry.refered = true;
                        entry.referedTime = System.currentTimeMillis();
                        tempPoolList.add(entry);
                    }
                    return entry.value;
                }
            }
        }
        return null;
    }

    private PoolFactory(PoolUnitManager poolUnitManager)
    {
        this.poolUnitManager = poolUnitManager;
        poolList = new ArrayBlockingQueue<Entry>(defaultSize);
        for (int i = 0; i < defaultSize; i++)
        {
            Entry entry = initEntry();
            if (entry.value != null)
            {
                poolList.add(entry);
            }
        }
        // 启动自清理定时器
        ThreadPool.getInstance().addTimer(new PoolCleanTask(),
                TimeUnit.SECONDS.toMillis(1), 10);

    }

    private Entry initEntry()
    {
        Object obj = poolUnitManager.newInstance();
        Entry entry = new Entry();
        entry.refered = false;
        entry.value = obj;
        if (obj != null)
        {
            poolUnitManager.initialize(obj);
        }
        return entry;
    }

    private class Entry
    {
        /**
         * 该对象是否被引用
         */
        boolean refered;

        /**
         * 被引用的时间点,若未被引用,则为0
         */
        long referedTime;

        /**
         * 数据池中存储的数据对象
         */
        Object value;
    }

    /**
     * 实现数据池自动清理功能
     */
    class PoolCleanTask extends TimerTask
    {

        @Override
        public void run()
        {
            long curTime = System.currentTimeMillis();
            // 清理常驻数据池
            for (Entry e : PoolFactory.this.poolList)
            {
                if (e.refered && poolUnitManager.releaseCondition(e.value))
                {
                    // System.out.println("回收常驻内存对象:" + e.value);
                    poolUnitManager.initialize(e.value);
                    e.refered = false;
                    e.referedTime = 0;
                }
                // 超时的元素将进行销毁处理被抛弃
                else if (e.referedTime > 0
                        && curTime - e.referedTime > expiredTime)
                {
                    e.value = null;
                    poolList.remove(e);
                    System.out.println("丢弃超时常驻内存对象");
                    Entry entry = initEntry();
                    if (entry.value != null)
                    {
                        System.out.println("补充元素");
                        poolList.add(entry);
                    }
                }
            }
            // 清理临时数据池
            if (tempPoolList != null)
                for (Entry e : PoolFactory.this.tempPoolList)
                {
                    if (e.refered == false)// 未被引用则清理
                    {
                        tempPoolList.remove(e);
                    }
                    else if (poolUnitManager.releaseCondition(e.value))// 若符合回收条件,则进行二次应用处理
                    {
                        // System.out.println("清理临时对象:" + e.value);
                        poolUnitManager.initialize(e.value);
                        e.refered = false;
                        e.referedTime = 0;
                    }// 超时的元素将进行销毁处理被抛弃
                    else if (e.referedTime > 0
                            && curTime - e.referedTime > expiredTime)
                    {
                        e.value = null;
                        tempPoolList.remove(e);
                        System.out.println("丢弃超时临时对象");
                    }
                }
        }
    }
}
